// SPDX-License-Identifier: Apache-2.0
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

// 定义以太网类型常量：IPv4 和源路由专用类型
const bit<16> TYPE_IPV4 = 0x800;
const bit<16> TYPE_SRCROUTING = 0x1234;
// 定义最大跳数（源路由栈的最大条目数）
#define MAX_HOPS 9

/*************************************************************************
*********************** 头部类型定义（HEADERS） *************************
*************************************************************************/
// 定义出端口类型（适配v1model架构）
typedef bit<9>  egressSpec_t;
// 定义MAC地址类型（48位）
typedef bit<48> macAddr_t;
// 定义IPv4地址类型（32位）
typedef bit<32> ip4Addr_t;

// 以太网头部
header ethernet_t {
    macAddr_t dstAddr;   // 目的MAC地址
    macAddr_t srcAddr;   // 源MAC地址
    bit<16>   etherType; // 以太网类型（区分IPv4/源路由）
}

// 源路由头部（单个路由条目）
header srcRoute_t {
    bit<1>    bos;  // 栈底标识（1=最后一个条目，0=还有后续条目）
    bit<15>   port; // 出端口号（指导交换机转发的端口）
}

// IPv4头部（标准IPv4格式）
header ipv4_t {
    bit<4>    version;    // 版本（IPv4为4）
    bit<4>    ihl;        // 头部长度（以32位字为单位）
    bit<8>    diffserv;   // 区分服务字段
    bit<16>   totalLen;   // 总长度（头部+数据）
    bit<16>   identification; // 标识（用于分片重组）
    bit<3>    flags;      // 标志（分片控制）
    bit<13>   fragOffset; // 分片偏移
    bit<8>    ttl;        // 生存时间（每跳减1，防止环路）
    bit<8>    protocol;   // 上层协议（如TCP=6，UDP=17）
    bit<16>   hdrChecksum;// 头部校验和
    ip4Addr_t srcAddr;    // 源IPv4地址
    ip4Addr_t dstAddr;    // 目的IPv4地址
}

// 元数据结构
struct metadata {
    bit<32> routing_type; // 0: IPv4转发, 1: 源路由
}

// 头部集合（包含以太网头、源路由栈、IPv4头）
struct headers {
    ethernet_t              ethernet;       // 以太网头部
    srcRoute_t[MAX_HOPS]    srcRoutes;      // 源路由栈（最多MAX_HOPS个条目）
    ipv4_t                  ipv4;           // IPv4头部
}

/*************************************************************************
*********************** 解析器（PARSER） *******************************
*************************************************************************/
parser MyParser(
    packet_in packet,          // 入方向数据包
    out headers hdr,           // 输出解析后的头部
    inout metadata meta,       // 元数据（入出）
    inout standard_metadata_t standard_metadata // 标准元数据（如入端口）
) {
    state start {
        transition parse_ethernet;
    }

    state parse_ethernet {
        packet.extract(hdr.ethernet);
        transition select(hdr.ethernet.etherType) {
            TYPE_SRCROUTING: parse_srcRouting;
            TYPE_IPV4: parse_ipv4;
            default: accept;
        }
    }

    state parse_srcRouting {
        meta.routing_type = 1; // 标记为源路由数据包
        packet.extract(hdr.srcRoutes.next);
        transition select(hdr.srcRoutes.last.bos) {
            0: parse_srcRouting;
            1: parse_ipv4;
        }
    }

    state parse_ipv4 {
        if (meta.routing_type != 1) {
            meta.routing_type = 0; // 标记为普通IPv4数据包
        }
        packet.extract(hdr.ipv4);
        transition accept;
    }
}

/*************************************************************************
*********************** 校验和验证 ***************************
*************************************************************************/
control MyVerifyChecksum(
    inout headers hdr, 
    inout metadata meta
) {
    apply {  }
}

/*************************************************************************
*********************** 入方向处理（核心逻辑） *************************
*************************************************************************/
control MyIngress(
    inout headers hdr,
    inout metadata meta,
    inout standard_metadata_t standard_metadata
) {
    // IPv4转发相关动作
    action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
        // 设置目的MAC地址
        hdr.ethernet.dstAddr = dstAddr;
        // 设置出端口
        standard_metadata.egress_spec = port;
        // 递减TTL
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
    }

    action drop() {
        mark_to_drop(standard_metadata);
    }

    // 源路由相关动作
    action srcRoute_nhop() {
        standard_metadata.egress_spec = (egressSpec_t) hdr.srcRoutes[0].port;
        hdr.srcRoutes.pop_front(1);
    }

    action srcRoute_finish() {
        hdr.ethernet.etherType = TYPE_IPV4;
    }

    // 定义表
    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: lpm;
        }
        actions = {
            ipv4_forward;
            drop;
            NoAction;
        }
        size = 1024;
        default_action = drop();
    }

    apply {
        // 根据路由类型选择处理路径
        if (meta.routing_type == 1) {
            // 源路由处理
            if (hdr.srcRoutes[0].isValid()) {
                if (hdr.srcRoutes[0].bos == 1) {
                    srcRoute_finish();
                }
                srcRoute_nhop();
                if (hdr.ipv4.isValid()) {
                    hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
                }
            } else {
                drop();
            }
        } else {
            // IPv4转发处理
            if (hdr.ipv4.isValid()) {
                ipv4_lpm.apply();
            }
        }
    }
}

/*************************************************************************
*********************** 出方向处理 ***************************
*************************************************************************/
control MyEgress(
    inout headers hdr,
    inout metadata meta,
    inout standard_metadata_t standard_metadata
) {
    apply {  }
}

/*************************************************************************
*********************** 校验和计算 ***************************
*************************************************************************/
control MyComputeChecksum(
    inout headers hdr, 
    inout metadata meta
) {
    apply {  }
}

/*************************************************************************
*********************** 解解析器 *************************
*************************************************************************/
control MyDeparser(
    packet_out packet,
    in headers hdr
) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.srcRoutes);
        packet.emit(hdr.ipv4);
    }
}

/*************************************************************************
*********************** 交换机实例化 **********************
*************************************************************************/
V1Switch(
    MyParser(),
    MyVerifyChecksum(),
    MyIngress(),
    MyEgress(),
    MyComputeChecksum(),
    MyDeparser()
) main;